#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"

#include "klib/dbm.hpp"
#include "klib/utils.hpp"
#include "klib/net.hpp"
#include <cinttypes>
#include <set>

using namespace klib;
using namespace klib::dbm;

const char DB_NAME[] = "1.kdb";

TEST_CASE("kdb") {
    const char *value_fmt = "value is {}";

    rand_t rand;
    uint64_t key;

    std::remove(DB_NAME);

    dbm_t db;
    DOCTEST_REQUIRE(db.open(DB_NAME));

    std::set<uint64_t> ids;

    klib::dstring_t ds;
    for (int i = 0; i < 10; i++) {
        key = rand.next();
        ids.insert(key);
        ds.resize(0);
        ds.format(value_fmt, key);
        uint64_t k = net::h2n(key);
        db.store(value_t(&k), value_t(ds));
    }

    // 验证是否全部插入
    auto ids_copy(ids);
    for (auto i : ids) {
        auto key = net::h2n(i);
        uni_value_t val = db.fetch(value_t(&key));
        klib::dstring_t v(std::string_view(val.data, val.size));
        ds.resize(0);
        ds.format(value_fmt, i);
        DOCTEST_CHECK_MESSAGE(ds == v, fmt::format_string("value = {}, expect = {}", v, ds));
    }

    // 删除第一条记录
    auto rk = *ids.begin();
    ids.erase(*ids.begin());
    rk = net::h2n(rk);
    db.erase(value_t(&rk));

    // 查找所有键值，验证是否正确
    for (auto iter : db) {
        auto n = net::n2h(iter.value<uint64_t>());
        ids.erase(n);
    }
    DOCTEST_CHECK(ids.size() == 0);
}